package com.sc.nft.dao;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sc.nft.dto.OrderDTO;
import com.sc.nft.entity.Order;
import com.sc.nft.entity.dto.OrderDetailsDTO;
import com.sc.nft.entity.dto.RefundOrderPageDTO;
import com.sc.nft.entity.vo.OrderDetailListVO;
import com.sc.nft.entity.vo.OrderPageWebVO;
import com.sc.nft.entity.vo.OrderSimpleVO;
import com.sc.nft.entity.vo.RefundOrderPageVO;
import com.sc.nft.enums.ClassifyType;
import com.sc.nft.enums.OrderStatusEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.mapper.OrderMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 订单表(sc_order)数据DAO
 *
 * @author zxy
 * @description 由 Mybatisplus Code Generator 创建
 * @since 2022-06-02 01:04:25
 */
@Slf4j
@Repository
public class OrderDao extends ServiceImpl<OrderMapper, Order> {

    public Order getByOrderNo(String orderNo) {
        return new LambdaQueryChainWrapper<Order>(baseMapper).eq(Order::getOrderNo, orderNo).one();

    }

    public IPage<OrderPageWebVO> orderPage(Long userId, OrderStatusEnum orderStatus, ClassifyType orderType, int pageNo, int pageSize) {
        if (orderStatus.getCode() == OrderStatusEnum.ALL.getCode()) {
            return new LambdaQueryChainWrapper<Order>(baseMapper).eq(Order::getUserId, userId).orderByDesc(Order::getId).page(new Page<>(pageNo, pageSize)).convert(order ->{
                OrderPageWebVO orderPageWebVO =new OrderPageWebVO();
                BeanUtil.copyProperties(order, orderPageWebVO);
                orderPageWebVO.setProductPrice(order.getProductPrice());
                return orderPageWebVO;
            });
        }
        return new LambdaQueryChainWrapper<Order>(baseMapper).eq(Order::getUserId, userId).eq(orderStatus != null, Order::getStatus, orderStatus).orderByDesc(Order::getId).page(new Page<>(pageNo, pageSize)).convert(order ->{
            OrderPageWebVO orderPageWebVO =new OrderPageWebVO();
            BeanUtil.copyProperties(order, orderPageWebVO);
            orderPageWebVO.setProductPrice(order.getProductPrice());
            return orderPageWebVO;
        } );
    }

    public Order getOrderByProductAndUserId(Long userId, Long productId) {
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getStatus, OrderStatusEnum.WAIT_PAY);
        wrapper.eq(Order::getUserId, userId);
        wrapper.eq(Order::getProductId, productId);
        wrapper.last("limit 1");
        return getOne(wrapper);
    }

    public List<Order> getCloseOrder() {
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.lt(Order::getCloseTime, DateTime.now());
        wrapper.eq(Order::getStatus, OrderStatusEnum.WAIT_PAY);
        return list(wrapper);
    }

    public boolean closeOrder(Long id) {
        LambdaUpdateWrapper<Order> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(Order::getStatus,OrderStatusEnum.CLOSE);
        wrapper.eq(Order::getId,id);
        wrapper.eq(Order::getStatus,OrderStatusEnum.WAIT_PAY);
        return update(wrapper);

    }

    public List<Order> getListByProductIdAndStaus(Long productId, OrderStatusEnum orderStatusEnum, Long userId, Boolean isBuyFirst) {
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getProductId, productId);
        wrapper.eq(Order::getStatus, orderStatusEnum);
        wrapper.eq(Order::getUserId, userId);
        wrapper.eq(Order::getIsBuyFirst, isBuyFirst);
        return list(wrapper);
    }

    public List<Order> getListByStatusAndIsCloce() {
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getStatus, OrderStatusEnum.PAYMENT);
        wrapper.eq(Order::getIsClose, Boolean.FALSE);
        return list(wrapper);
    }

    public Page<Order> orderPageForAdmin(Long userId, String orderNo, Long productId, OrderStatusEnum status, Date startOrderTime, Date endOrderTime, Date startPayTime, Date endPayTime, int pageNo, int pageSize) {
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(userId != null, Order::getUserId, userId);
        wrapper.eq(StrUtil.isNotBlank(orderNo), Order::getOrderNo, orderNo);
        wrapper.eq(productId != null, Order::getProductId, productId);
        wrapper.eq(status != null && status != OrderStatusEnum.ALL, Order::getStatus, status);
        wrapper.le(startOrderTime != null, Order::getOrderTime, userId);
        wrapper.ge(endOrderTime != null, Order::getOrderTime, endOrderTime);
        wrapper.le(startPayTime != null, Order::getPayTime, startPayTime);
        wrapper.ge(endPayTime != null, Order::getPayTime, endPayTime);
        return page(new Page<>(pageNo, pageSize), wrapper);
    }

    public List<OrderSimpleVO> orderExport(Long productId) {
        return baseMapper.orderExport(productId);
    }

    public List<OrderDetailListVO> orderDetailExport(Long productId, Date payTimeFrom, Date payTimeTo) {
        return baseMapper.orderDetailExport(productId, payTimeFrom, payTimeTo);
    }

    public Page<OrderDTO> orderDTOPageForAdmin(String firstTitle, Long userId, String orderNo, Long productId, OrderStatusEnum status, Date startOrderTime, Date endOrderTime, Date startPayTime, Date endPayTime, int pageNo, int pageSize) {
        if (status != null && status == OrderStatusEnum.ALL){
            status = null;
        }
        return baseMapper.orderDTOPageForAdmin(new Page(pageNo,pageSize), firstTitle, userId,orderNo,productId,status,startOrderTime,endOrderTime,startPayTime,endPayTime);
    }

    public OrderDetailsDTO getOrderDetailsById(Long id) {
        return baseMapper.getOrderDetailsById(id);
    }

    public Object getOrderStatus(String orderNo) {
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getStatus, OrderStatusEnum.PAYMENT);
        wrapper.eq(Order::getOrderNo, orderNo);
        wrapper.last("limit 1");
        return getOne(wrapper);
    }

    /**
     * 某个用户优先抢成功的总数量
     *
     * @param productId
     * @param userId
     * @return
     */
    public int getRushBuySumByProductIdAndStausAndUserId(Long productId, Long userId) {
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getProductId, productId);
        wrapper.in(Order::getStatus, OrderStatusEnum.PAYMENT.getCode(), OrderStatusEnum.WAIT_PAY.getCode());
        wrapper.eq(Order::getUserId, userId);
        wrapper.eq(Order::getIsRushBuy, Boolean.TRUE);
        List<Order> list = list(wrapper);

        return list.stream().mapToInt(Order::getCount).sum();
    }

    /**
     * 某个商品优先抢已售数量
     *
     * @param productId
     * @return
     */
    public int getRushBuySumListByProductIdAndStaus(Long productId) {
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getProductId, productId);
        wrapper.in(Order::getStatus, OrderStatusEnum.PAYMENT.getCode(), OrderStatusEnum.WAIT_PAY.getCode());
        wrapper.eq(Order::getIsRushBuy, Boolean.TRUE);
        List<Order> list = list(wrapper);

        return list.stream().mapToInt(Order::getCount).sum();
    }

    /**
     * 某个商品优先购已售数量
     * @param productId
     * @return
     */
    public int getFirstPaysumListByProductIdAndStaus(Long productId) {
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getProductId, productId);
        wrapper.in(Order::getStatus, OrderStatusEnum.PAYMENT.getCode(), OrderStatusEnum.WAIT_PAY.getCode());
        wrapper.eq(Order::getIsBuyFirst, Boolean.TRUE);
        List<Order> list = list(wrapper);
        return list.stream().mapToInt(Order::getCount).sum();
    }

    public List<Order> getListByStatusAndUserId(Long userId, OrderStatusEnum status) {
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getUserId, userId);
        wrapper.eq(Order::getStatus, status);
        return list(wrapper);
    }

    public List<Order> getListByStatusAndProductId(Long productId, OrderStatusEnum status) {
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getProductId, productId);
        wrapper.eq(Order::getStatus, status);
        return list(wrapper);
    }






    /**
     * @param start   起始条目
     * @param end     结束条目
     * @param orderId 查询区间订单号
     * @return
     */
    public Integer findLimitBetween(Long start, Long end, Long orderId,Integer collectionId) {
        return baseMapper.findLimitBetween(start, end, orderId,collectionId);
    }

    public Integer findLimitBetweenSum(Integer collectionId) {
        return baseMapper.findLimitBetweenSum(collectionId);
    }


    public Integer getSumCountByProductId(List<Long> productId) {
        return baseMapper.getSumCountByProductId(productId);
    }

    public BigDecimal getToDaySellAmount() {
        return baseMapper.getToDaySellAmount();
    }

    public BigDecimal getAllSumSellAmount() {
        return baseMapper.getAllSumSellAmount();
    }

    public Integer getToDaySellCount() {
        return baseMapper.getToDaySellCount();
    }

    public Integer getToDaySellCountByDay(String day) {
        return baseMapper.getToDaySellCountByDay(day);
    }

    public Integer getToDaySellBuyUserCount() {
        return baseMapper.getToDaySellBuyUserCount();
    }

    public Integer getToDaySellBuyUserCountByDay(String day) {
        return baseMapper.getToDaySellBuyUserCountByDay(day);
    }

    public BigDecimal getToDaySellAmountByDay(String day) {
        return baseMapper.getToDaySellAmountByDay(day);
    }

    public BigDecimal getAllSumSellAmountByDay(String day) {
        return baseMapper.getAllSumSellAmountByDay(day);
    }

    public Integer getYesterDayCountByCollectionId(Long collectionId) {
        return baseMapper.getYesterDayCountByCollectionId(collectionId);
    }

    public Integer getYesterDayCountByCollectionIdByDay(Long collectionId,String day) {
        return baseMapper.getYesterDayCountByCollectionIdByDay(collectionId,day);
    }

    public Integer getCountByProductId(Long productId) {
        return baseMapper.getCountByProductId(productId);
    }




    /**
     * 查询待结算业绩订单
     * @return
     */
    public List<Order> getWithSettlePerformance(){
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(Order::getId,Order::getUserId,Order::getProductPrice,Order::getOrderTime,Order::getShareProfitPanelId);
        wrapper.eq(Order::getStatus,OrderStatusEnum.PAYMENT);
        wrapper.eq(Order::getPerformanceSettleFlag,false);
        wrapper.last("limit 20000");
        return list(wrapper);
    }

    public void allReadySettleFlag(Long id ){
        Assert.isTrue(lambdaUpdate().eq(Order::getSettleFlag,false).eq(Order::getId,id).set(Order::getSettleFlag,true).update(),()-> new GlobalRunTimeException("订单结算状态更新失败"));
    }

    public void allReadyPerformanceSettleFlag(Long id ){
        Assert.isTrue(lambdaUpdate().eq(Order::getPerformanceSettleFlag,false).eq(Order::getId,id).set(Order::getPerformanceSettleFlag,true).update(),()-> new GlobalRunTimeException("订单业绩结算状态更新失败"));
    }


    /**
     * 获取退款sql.
     * @param request
     * @return
     */
    public IPage<RefundOrderPageVO> refundOrderPage(RefundOrderPageDTO request,Long userId) {
        LambdaQueryWrapper<Order> wrapper = Wrappers.lambdaQuery();
        wrapper.select(Order::getOrderNo,
                Order::getFirstTitle,
                Order::getProductPrice,
                Order::getCount,
                Order::getStatus,
                Order::getCreateTime,
                Order::getPayTime);
        wrapper.eq(Order::getUserId,userId);
        wrapper.eq(request.getStatus()!=null,Order::getStatus,request.getStatus());
        wrapper.eq(StrUtil.isNotEmpty(request.getOrderNo()),Order::getOrderNo,request.getOrderNo());
        wrapper.orderByDesc(Order::getId);
        Page page = page(request.toMp(), wrapper);
        List<Order> records = page.getRecords();
        List<RefundOrderPageVO>list=new ArrayList<>();
        records.forEach(order -> {
            RefundOrderPageVO refundOrderPageVO=new RefundOrderPageVO();
            refundOrderPageVO.setBuyPrice(order.getProductPrice());
            refundOrderPageVO.setOrderNo(order.getOrderNo());
            refundOrderPageVO.setFirstTitle(order.getFirstTitle());
            refundOrderPageVO.setCount(order.getCount());
            refundOrderPageVO.setStatus(order.getStatus());
            refundOrderPageVO.setPayTime(order.getPayTime());
            refundOrderPageVO.setCreateTime(order.getCreateTime());
            list.add(refundOrderPageVO);
        });
        page.setRecords(list);
        return page;
    }
}